<template>
  <div>
    <a-tabs v-model:activeKey="activeKey" type="card">
      <a-tab-pane key="1" tab="验证管理">
        <a-alert message="安全提示：" type="warning" show-icon style="margin-bottom: 18px">
          <template #description>
            验证码密钥是构建龙远验证码请求的重要凭证，为了您的财产和服务安全，请妥善保存。<br />
            请勿通过任何方式（如GitHub/Gitee）上传或者分享您的密钥信息，一旦泄露至外部渠道，可能造成您的资产损失。
          </template>
        </a-alert>
        <div class="table-page-search-wrapper">
          <a-row type="flex" justify="space-between" align="middle">
            <a-col :span="16">
              <a-form layout="inline" :model="listQuery">
                <a-form-item label="搜索项">
                  <a-input v-model:value="listQuery.title" placeholder="输入名称搜索..." />
                </a-form-item>
                <a-form-item>
                  <a-button type="primary" @click="searchSubmit"> 搜索 </a-button>
                </a-form-item>
              </a-form>
            </a-col>
            <a-col :span="8">
              <div style="margin-right: 0px; float: right; display: flex; align-item: center">
                <a-tooltip placement="top">
                  <template #title>
                    <span>刷新列表</span>
                  </template>
                  <a-button @click="reloadList">
                    <template #icon><SyncOutlined /></template>
                  </a-button>
                </a-tooltip>
                <a-button
                  v-permission="{ action: 'captcha_add' }"
                  type="primary"
                  style="margin-left: 12px"
                  @click="captcha_add"
                >
                  <template #icon><PlusOutlined /></template> 新增验证
                </a-button>
              </div>
            </a-col>
          </a-row>
        </div>
        <a-table
          :columns="columns"
          :rowKey="(record) => record.id"
          :dataSource="dataList.data"
          :loading="loading"
          :pagination="pagination"
          @change="handleTableChange"
        >
          <template #secret="{ text: record }">
            <div>AppId:{{ record.app_id }}</div>
            <div>
              AppSecret:<span v-if="secretShow[record.app_id] == true">{{ record.app_secret }}</span
              ><span v-else>*****</span>
              <a-button
                v-if="secretShow[record.app_id] == true"
                type="link"
                @click="
                  () => {
                    secretShow[record.app_id] = false
                  }
                "
                >隐藏</a-button
              >
              <a-button
                v-else
                type="link"
                @click="
                  () => {
                    secretShow[record.app_id] = true
                  }
                "
                >显示</a-button
              >
            </div>
          </template>
          <template #action="{ text: record }">
            <a v-permission="{ action: 'captcha_add' }" @click="captcha_edit(record)"
              ><EditOutlined /> 编辑</a
            >
            <a-divider type="vertical" />
            <a
              href="http://doc.21ds.cn/detail?doc=4731341806141859/4731341910749488"
              target="_blank"
              rel="noopener noreferrer"
              >系统代码集成</a
            >
            <a-divider v-permission="{ action: 'captcha_del' }" type="vertical" />
            <a
              v-permission="{ action: 'captcha_del' }"
              style="color: red"
              @click="captcha_delete(record)"
              ><DeleteOutlined /> 删除</a
            >
          </template>
        </a-table>
      </a-tab-pane>
      <a-tab-pane key="2" tab="验证统计">
        <div class="table-page-search-wrapper">
          <a-row type="flex" justify="space-between" align="middle">
            <a-col :span="12">
              <div>数据更新时间：{{ dataTime }} （不包含今日数据）</div>
            </a-col>
            <a-col :span="12">
              <div style="margin-right: 0px; float: right; display: flex; align-item: center">
                <a-radio-group v-model:value="listQuery.date_num" @change="changeDateNum">
                  <a-radio-button :value="-1">昨日</a-radio-button>
                  <a-radio-button :value="7">近7天</a-radio-button>
                  <a-radio-button :value="15">近15天</a-radio-button>
                  <a-radio-button :value="30">近30天</a-radio-button>
                </a-radio-group>
                <a-range-picker v-model:value="listQuery.date_range" @change="changeDate" />
              </div>
            </a-col>
          </a-row>
        </div>
        <div style="background-color: #ececec">
          <a-row>
            <a-tooltip placement="top">
              <template #title>
                <span>前端请求验证码接口的总量</span>
              </template>
              <a-col :sm="4" :xs="24">
                <a-card><a-statistic title="请求总量" :value="totalData.request" /></a-card>
              </a-col>
            </a-tooltip>
            <a-tooltip placement="top">
              <template #title>
                <span>总滑动次数,滑动一次+1</span>
              </template>
              <a-col :sm="4" :xs="24">
                <a-card><a-statistic title="验证总量" :value="totalData.verify" /></a-card>
              </a-col>
            </a-tooltip>
            <a-tooltip placement="top">
              <template #title>
                <span>后端票据校验的总量</span>
              </template>
              <a-col :sm="4" :xs="24">
                <a-card><a-statistic title="票据校验总量" :value="totalData.ticket" /></a-card>
              </a-col>
            </a-tooltip>

            <a-tooltip placement="top">
              <template #title>
                <span>前端行为验证，及安全策略通过总量</span>
              </template>
              <a-col :sm="4" :xs="24">
                <a-card><a-statistic title="通过总量" :value="totalData.verify_success" /></a-card>
              </a-col>
            </a-tooltip>

            <a-tooltip placement="top">
              <template #title>
                <span>前端行为验证，及安全策略未通过总量</span>
              </template>
              <a-col :sm="4" :xs="24">
                <a-card><a-statistic title="未通过总量" :value="totalData.verify_fail" /></a-card>
              </a-col>
            </a-tooltip>

            <a-tooltip placement="top">
              <template #title>
                <span>未通过总量在验证总量中的占比</span>
              </template>
              <a-col :sm="4" :xs="24">
                <a-card
                  ><a-statistic title="未通过总占比" :value="totalData.verify_fail_rate" suffix="%"
                /></a-card>
              </a-col>
            </a-tooltip>
          </a-row>
        </div>
        <div id="all_line" style="margin-top: 20px"></div>
        <a-divider />
        <div style="margin-top: 20px; font-weight: bold">单验证统计</div>
        <div class="table-page-search-wrapper" style="margin-top: 20px">
          <a-row type="flex" justify="space-between" align="middle">
            <a-col :span="12">
              <a-select
                v-model:value="listQuerySingle.app_id"
                style="width: 260px"
                placeholder="请选择验证应用"
              >
                <a-select-option
                  v-for="(item, index) in allCaptcheData"
                  :key="index"
                  :value="item.app_id"
                  >{{ item.title }}</a-select-option
                >
              </a-select>
            </a-col>
            <a-col :span="12">
              <div style="margin-right: 0px; float: right; display: flex; align-item: center">
                <a-radio-group
                  v-model:value="listQuerySingle.date_num"
                  @change="changeDateNumSingle"
                >
                  <a-radio-button :value="0">今日</a-radio-button>
                  <a-radio-button :value="7">近7天</a-radio-button>
                  <a-radio-button :value="15">近15天</a-radio-button>
                  <a-radio-button :value="30">近30天</a-radio-button>
                </a-radio-group>
                <a-range-picker
                  v-model:value="listQuerySingle.date_range"
                  @change="changeDateSingle"
                />
              </div>
            </a-col>
          </a-row>
          <div style="margin-top: 20px; font-weight: bold">验证通过与拦截</div>
          <div id="single_line" style="margin-top: 20px"></div>
          <div style="margin-top: 20px; font-weight: bold">票据校验</div>
          <div id="ticket_line" style="margin-top: 20px"></div>
        </div>
      </a-tab-pane>
    </a-tabs>
    <a-drawer
      width="45%"
      title="验证详情"
      placement="right"
      :open="drawerShow"
      @close="
        () => {
          drawerShow = false
        }
      "
    >
      <template #extra>
        <a-button
          style="margin-right: 8px"
          @click="
            () => {
              drawerShow = false
            }
          "
          >取消</a-button
        >
        <a-button type="primary" @click="addItem">提交</a-button>
      </template>
      <a-form
        ref="formRef"
        :model="FormState"
        :rules="FormRule"
        :labelCol="labelCol"
        :wrapperCol="wrapperCol"
      >
        <a-form-item
          v-if="FormState.app_id != undefined && FormState.app_id.length > 0"
          label="AppId"
        >
          {{ FormState.app_id }}
        </a-form-item>
        <a-form-item
          v-if="FormState.app_id != undefined && FormState.app_id.length > 0"
          label="AppSecret"
        >
          {{ FormState.app_secret }}
          <a-button type="link" @click="resetSecret(FormState.app_id)">重置</a-button>
        </a-form-item>
        <a-form-item label="验证名称" has-feedback required name="title">
          <a-input v-model:value="FormState.title" placeholder="请输入验证名称" />
        </a-form-item>
        <a-form-item label="验证所属域名">
          <a-input
            v-model:value="FormState.domain"
            placeholder="多域名请使用英文逗号','分割，如:（example1.com,example2.com）"
          />
        </a-form-item>
        <a-form-item label="验证渠道" has-feedback required name="type">
          <a-radio-group v-model:value="FormState.type" name="type">
            <a-radio key="web" value="web">Web端/App(IOS或Android)</a-radio>
          </a-radio-group>
        </a-form-item>
        <a-form-item label="验证场景" has-feedback required name="scene">
          <a-radio-group v-model:value="FormState.scene" name="scene">
            <a-radio key="account" value="account">账号场景(登录、注册等)</a-radio>
            <a-radio key="sms" value="sms">短信场景(短信/邮箱验证码)</a-radio><br />
            <a-radio key="active" value="active">活动场景(秒杀、领券等)</a-radio>
            <a-radio key="other" value="other">其他场景(评论、投票等)</a-radio>
          </a-radio-group>
        </a-form-item>
      </a-form>
    </a-drawer>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, onMounted, ref, toRaw, createVNode, watch } from 'vue'
import {
  Row,
  Col,
  Modal,
  Divider,
  Drawer,
  Card,
  Tooltip,
  Statistic,
  RadioGroup,
  RangePicker
} from 'ant-design-vue'
import {
  SyncOutlined,
  PlusOutlined,
  EditOutlined,
  DeleteOutlined,
  ExclamationCircleOutlined,
  DownOutlined
} from '@ant-design/icons-vue'
import { requestSuccess, requestFailed } from '@/utils/feedback'
import {
  delArtItem,
  getItemList,
  editData,
  resetAppSecret,
  allCaptchaData,
  getAllCaptcha,
  allTicketData
} from '@/api/captcha'
import { useRouter } from 'vue-router'
import { todayDate, getRangeDate } from '@/utils/common'
import dayjs, { Dayjs } from 'dayjs'
import { Line } from '@antv/g2plot'

export default defineComponent({
  name: 'Captcha',
  components: {
    SyncOutlined,
    PlusOutlined,
    EditOutlined,
    ExclamationCircleOutlined,
    DownOutlined,
    DeleteOutlined,
    [Row.name]: Row,
    [Card.name]: Card,
    [Tooltip.name]: Tooltip,
    [RadioGroup.name]: RadioGroup,
    [RangePicker.name]: RangePicker,
    [Divider.name]: Divider,
    [Statistic.name]: Statistic,
    [Drawer.name]: Drawer,
    [Col.name]: Col
  },
  setup() {
    const formRef = ref()
    const router = useRouter()
    const dateFormat = 'YYYY-MM-DD'
    const state = reactive<any>({
      loading: true,
      drawerShow: false,
      today: todayDate(),
      dataList: [],
      allCaptcheData: [],
      secretShow: {},
      totalData: {},
      allLineRender: '',
      singleLineRender: '',
      ticketLineRender: '',
      dataTime: '',
      allLine: ref(),
      singleLine: ref(),
      ticketLine: ref(),
      activeKey: ref('1'),
      listQuery: {
        pageNo: 1,
        pageSize: 15,
        date_range: [],
        date_range_format: [],
        date_num: -1
      },
      listQuerySingle: {
        app_id: '',
        date_range: [],
        date_range_format: [],
        date_num: 0
      },
      pagination: {
        pageSizeOptions: ['15', '30', '50'],
        showSizeChanger: true,
        total: 1,
        showTotal: (total) => `共 ${total} 条数据`,
        pageSize: 15,
        current: 1
      },
      labelCol: {
        xs: { span: 24 },
        sm: { span: 3 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 20 }
      },
      columns: [
        {
          title: '名称',
          dataIndex: 'title'
        },
        {
          title: '渠道',
          dataIndex: 'type_tip'
        },
        {
          title: '密钥',
          width: '450px',
          slots: { customRender: 'secret' }
        },
        {
          title: '昨日拦截占比',
          dataIndex: 'yesterday_verify_fail_rate'
        },
        {
          title: '昨日请求量',
          dataIndex: 'yesterday_request'
        },
        {
          title: '昨日验证量',
          dataIndex: 'yesterday_verify'
        },
        {
          title: '昨日拦截量',
          dataIndex: 'yesterday_verify_fail'
        },
        {
          title: '创建时间',
          dataIndex: 'create_time'
        },
        {
          title: '操作',
          width: '250px',
          slots: { customRender: 'action' }
        }
      ]
    })
    onMounted(() => {
      getDataList()
    })

    watch(
      () => state.activeKey,
      () => {
        if (state.activeKey == 1) {
          getDataList()
        } else {
          getRangeDay()
          getAllCaptchaData()
          getRangeDaySingle('auto')
        }
      }
    )
    watch(
      () => state.listQuerySingle.app_id,
      () => {
        getRangeDayDataSingle()
      }
    )

    function changeDateNum(e) {
      state.listQuery.date_num = e.target.value
      getRangeDay()
    }
    function changeDateNumSingle(e) {
      state.listQuerySingle.date_num = e.target.value
      getRangeDaySingle('click')
    }

    function getRangeDaySingle(operate) {
      let end = ''
      let start = ''
      end = getRangeDate(0)
      start = end
      if (state.listQuerySingle.date_num != 0) {
        start = getRangeDate(state.listQuerySingle.date_num * -1)
      }
      state.listQuerySingle.date_range = ref<[Dayjs, Dayjs]>([
        dayjs(start, dateFormat),
        dayjs(end, dateFormat)
      ])
      if (operate == 'auto') {
        setTimeout(() => {
          console.log(operate)
          getRangeDayDataSingle()
        }, 1000)
      } else {
        getRangeDayDataSingle()
      }
    }
    function getRangeDay() {
      let end = ''
      let start = ''
      end = getRangeDate(-1)
      start = end
      if (state.listQuery.date_num != -1) {
        start = getRangeDate(state.listQuery.date_num * -1)
      }
      state.listQuery.date_range = ref<[Dayjs, Dayjs]>([
        dayjs(start, dateFormat),
        dayjs(end, dateFormat)
      ])
      setTimeout(() => {
        getRangeDayData()
      }, 200)
    }
    function changeDate(e) {
      state.listQuery.date_range = e
      getRangeDayData()
    }
    function changeDateSingle(e) {
      state.listQuerySingle.date_range = e
      getRangeDayDataSingle()
    }
    function getRangeDayDataSingle() {
      state.listQuerySingle.date_range_format[0] =
        state.listQuerySingle.date_range[0].format(dateFormat)
      state.listQuerySingle.date_range_format[1] =
        state.listQuerySingle.date_range[1].format(dateFormat)
      allCaptchaData(state.listQuerySingle).then((res) => {
        let data = res.data.chart
        if (state.singleLineRender == 'update') {
          state.singleLine.update({
            data
          })
        } else {
          state.singleLine = new Line('single_line', {
            data,
            xField: 'date',
            smooth: true,
            yField: 'value',
            seriesField: 'category',
            yAxis: {
              label: {
                // 数值格式化为千分位
                formatter: (v) => `${v}`.replace(/\d{1,3}(?=(\d{3})+$)/g, (s) => `${s},`)
              }
            }
          })
          state.singleLine.render()
          state.singleLineRender = 'update'
        }
      })
      getTicketData()
    }
    function getRangeDayData() {
      state.listQuery.date_range_format[0] = state.listQuery.date_range[0].format(dateFormat)
      state.listQuery.date_range_format[1] = state.listQuery.date_range[1].format(dateFormat)
      allCaptchaData(state.listQuery).then((res) => {
        state.totalData = res.data.total
        state.dataTime = res.data.date
        let data = res.data.chart
        if (state.allLineRender == 'update') {
          state.allLine.update({
            data
          })
        } else {
          state.allLine = new Line('all_line', {
            data,
            xField: 'date',
            smooth: true,
            yField: 'value',
            seriesField: 'category',
            yAxis: {
              label: {
                // 数值格式化为千分位
                formatter: (v) => `${v}`.replace(/\d{1,3}(?=(\d{3})+$)/g, (s) => `${s},`)
              }
            }
          })
          state.allLine.render()
          state.allLineRender = 'update'
        }
      })
    }
    function getTicketData() {
      state.listQuerySingle.date_range_format[0] =
        state.listQuerySingle.date_range[0].format(dateFormat)
      state.listQuerySingle.date_range_format[1] =
        state.listQuerySingle.date_range[1].format(dateFormat)
      allTicketData(state.listQuerySingle).then((res) => {
        let data = res.data.chart
        if (state.ticketLineRender == 'update') {
          state.ticketLine.update({
            data
          })
        } else {
          state.ticketLine = new Line('ticket_line', {
            data,
            xField: 'date',
            smooth: true,
            yField: 'value',
            seriesField: 'category',
            yAxis: {
              label: {
                // 数值格式化为千分位
                formatter: (v) => `${v}`.replace(/\d{1,3}(?=(\d{3})+$)/g, (s) => `${s},`)
              }
            }
          })
          state.ticketLine.render()
          state.ticketLineRender = 'update'
        }
      })
    }
    function getAllCaptchaData() {
      getAllCaptcha({}).then((res) => {
        state.listQuerySingle.app_id = res[0].app_id
        state.allCaptcheData = res
      })
    }

    const FormState = reactive<any>({
      title: '',
      domain: '',
      scene: '',
      type: ''
    })
    const FormRule = {
      title: [{ required: true, message: '请输入标题', trigger: ['blur', 'change'] }],
      scene: [{ required: true, message: '请选择验证场景', trigger: ['blur', 'change'] }],
      type: [{ required: true, message: '请选择验证渠道', trigger: ['blur', 'change'] }]
    }

    function handleTableChange(e) {
      state.loading = true
      state.pagination.pageSize = e.pageSize
      state.listQuery.pageSize = e.pageSize
      state.listQuery.pageNo = e.current
      state.pagination.current = e.current
      getDataList()
    }

    function reloadList() {
      state.loading = true
      state.listQuery.pageNo = 1
      state.pagination.current = 1
      getDataList()
    }

    function searchSubmit() {
      state.loading = true
      state.listQuery.pageNo = 1
      state.pagination.current = 1
      getDataList()
    }
    function resetSecret(app_id) {
      Modal.confirm({
        title: '确认重置AppSecret?',
        icon: createVNode(ExclamationCircleOutlined),
        content: '确认后原AppSecret将于5分钟后正式失效',
        okText: '确认',
        okType: 'danger',
        cancelText: '取消',
        onOk() {
          resetAppSecret({ id: app_id }).then((res) => {
            if (res.code === 200) {
              requestSuccess(res)
              state.loading = true
              state.drawerShow = false
              reloadList()
            } else {
              requestFailed(res)
            }
          })
        }
      })
    }
    function captcha_edit(res) {
      for (let item in FormState) {
        FormState[item] = ''
      }
      for (let item in res) {
        FormState[item] = res[item]
      }
      state.drawerShow = true
    }
    function captcha_add() {
      for (let item in FormState) {
        FormState[item] = ''
      }
      state.drawerShow = true
    }

    function getDataList() {
      getItemList(state.listQuery).then((res) => {
        state.loading = false
        state.dataList = res
        for (let index = 0; index < res.data.length; index++) {
          const element = res.data[index]
          state.secretShow[element.app_id] = false
        }
        state.pagination.total = res.totalCount
      })
    }
    const addItem = () => {
      formRef.value
        .validate()
        .then(() => {
          editData(toRaw(FormState)).then((res) => {
            if (res.code === 200) {
              requestSuccess(res)
              formRef.value.resetFields()
              state.loading = true
              state.drawerShow = false
              reloadList()
            } else {
              requestFailed(res)
            }
          })
        })
        .catch(() => {
          return false
        })
    }
    function captcha_delete(data) {
      Modal.confirm({
        title: '确认删除此验证?',
        content: '【' + data.title + '】',
        okType: 'danger',
        onOk() {
          delArtItem({ id: data.id }).then((res) => {
            if (res.code === 200) {
              state.loading = true
              reloadList()
              requestSuccess(res)
            } else {
              requestFailed(res)
            }
          })
        }
      })
    }
    return {
      ...toRefs(state),
      handleTableChange,
      reloadList,
      searchSubmit,
      captcha_delete,
      formRef,
      captcha_add,
      changeDateNum,
      changeDateNumSingle,
      resetSecret,
      FormState,
      captcha_edit,
      addItem,
      FormRule,
      router,
      changeDate,
      changeDateSingle,
      getDataList
    }
  }
})
</script>

<style scoped></style>
